home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / Utils / SWGameUtils.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  15.1 KB  |  508 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //    SWGameUtils.c
  3. //
  4. //    Portions are copyright: © 1991-94 Tony Myles, All rights reserved worldwide.
  5. //
  6. //    Description:    some utility functions for games. Thanks to Gareth White for
  7. //    the Control Strip functions.
  8. ///--------------------------------------------------------------------------------------
  9. #ifndef __LOWMEM__
  10. #include <LowMem.h>
  11. #endif
  12.  
  13. #ifndef __RESOURCES__
  14. #include <Resources.h>
  15. #endif
  16.  
  17. #include <ControlStrip.h>
  18. #include <Gestalt.h>
  19. #include <MixedMode.h>
  20. #include <Palettes.h>
  21. #include <QDOffscreen.h>
  22. #include <Traps.h>
  23.  
  24. #include <SWCommonHeaders.h>
  25. #include <SWGameUtils.h>
  26.  
  27.  
  28.  
  29. ///--------------------------------------------------------------------------------------
  30. //    Randomize - initialize random number seed
  31. ///--------------------------------------------------------------------------------------
  32.  
  33. void Randomize( void )
  34. {
  35.     GetDateTime( (unsigned long *)(&qd.randSeed) );
  36. }
  37.  
  38.  
  39. ///--------------------------------------------------------------------------------------
  40. //    GetRandom - generate a random number between min and max inclusive
  41. ///--------------------------------------------------------------------------------------
  42.  
  43. short GetRandom(short min, short max)
  44. {
  45.     unsigned short        random;
  46.     long                range, temp;
  47.  
  48.     random = Random();
  49.     range = (max - min) + 1;
  50.     temp = (random * range) / 65536;
  51.     random = temp + min;
  52.  
  53.     return random;
  54. }
  55.  
  56.  
  57. ///--------------------------------------------------------------------------------------
  58. //    GetUnsignedRandom - generate an unsigned random number between min and max inclusive
  59. //  You can get random numbers between 0 and 65535.
  60. ///--------------------------------------------------------------------------------------
  61.  
  62. unsigned short    GetUnsignedRandom(unsigned short min, unsigned short max)
  63. {
  64.     unsigned short    random;            // Note: unsigned short = UInt16
  65.     unsigned long    range, temp;
  66.  
  67.     random = Random();
  68.     range = (max - min) + 1;
  69.     temp = (random * range) / 65536;
  70.     random = temp + min;
  71.  
  72.     return random;
  73. }
  74.  
  75.  
  76. ///--------------------------------------------------------------------------------------
  77. //    CenterRect - centers rectA in rectB, returning result in rectA. This will work
  78. //  properly even when rectA is _larger_ than rectB, and will result in centering rectA
  79. //    around rectB.
  80. ///--------------------------------------------------------------------------------------
  81.  
  82. void CenterRect(Rect* rectA, Rect* rectB)
  83. {
  84.     short width = (rectA->right - rectA->left);
  85.     short height = (rectA->bottom - rectA->top);
  86.  
  87.     rectA->left = rectB->left + (((rectB->right - rectB->left) / 2) - (width / 2));
  88.     rectA->top = rectB->top + (((rectB->bottom - rectB->top) / 2) - (height / 2));
  89.     rectA->right = rectA->left + width;
  90.     rectA->bottom = rectA->top + height;
  91. }
  92.  
  93.  
  94. ///--------------------------------------------------------------------------------------
  95. //    AlignRect - aligns the rectangle so its left side is positioned on an even long word
  96. //    boundary. This would be every 4th pixel in 8-bit, and every 2nd in 16-bit. However,
  97. //    we just do every 4th pixel regardless of depth, since it's easier that way. :-)
  98. //    Besides, it means our rect will be aligned to double boundaries when in 16-bit.
  99. ///--------------------------------------------------------------------------------------
  100.  
  101. void    AlignRect(Rect* rectP)
  102. {
  103.     short    rectWidth, overflow;
  104.     
  105.     rectWidth = rectP->right - rectP->left;
  106.     overflow = rectP->left & 3;            // Save right two bits
  107.     
  108.     rectP->left = rectP->left>>2<<2;    // Eliminate right two bits (numbers 1-3)
  109.     
  110.     if (overflow > 2)                    // Round up if closer to right than to left
  111.         rectP->left += 4;                // (just a nice touch)
  112.     
  113.     rectP->right = rectP->left + rectWidth;
  114. }
  115.  
  116.  
  117. ///--------------------------------------------------------------------------------------
  118. // ResourceExists - returns true if the specified resource exists in the current resource
  119. // file.
  120. ///--------------------------------------------------------------------------------------
  121.  
  122. Boolean        ResourceExists(ResType resourceType, short resID)
  123. {
  124.     Boolean    doesExist;
  125.     Handle    resourceHandle;
  126.     
  127.     SetResLoad(false);
  128.  
  129.     resourceHandle = Get1Resource(resourceType, resID);
  130.     
  131.     if (resourceHandle != NULL)
  132.     {
  133.         doesExist = true;
  134.         ReleaseResource(resourceHandle);    // Free up this master pointer
  135.     }
  136.     else
  137.         doesExist = false;
  138.     
  139.     SetResLoad(true);
  140.     
  141.     return doesExist;
  142. }
  143.  
  144. #pragma mark -
  145.  
  146. short        gOldEventMask;    // Used by AllowKeyUpEvents and RestoreEventMask
  147. Boolean        eventMaskIsGood = false;
  148.  
  149. ///--------------------------------------------------------------------------------------
  150. //    AllowKeyUpEvents - allows keyUpEvents. Make sure to call RestoreEventMask
  151. //    before your program quits if you call AllowKeyUpEvents.
  152. ///--------------------------------------------------------------------------------------
  153.  
  154. void AllowKeyUpEvents( void )
  155. {
  156.     gOldEventMask = LMGetSysEvtMask();
  157.     SetEventMask(everyEvent);
  158.     
  159.         // Let RestoreEventMask know that the old mask has been saved
  160.     eventMaskIsGood = true;
  161. }
  162.  
  163.  
  164. ///--------------------------------------------------------------------------------------
  165. //    RestoreEventMask - call this before your program quits if you previously
  166. //    called AllowKeyUpEvents. This will beep if you didn't call AllowKeyUpEvents first.
  167. ///--------------------------------------------------------------------------------------
  168.  
  169. void RestoreEventMask( void )
  170. {
  171.     if (eventMaskIsGood)
  172.         SetEventMask(gOldEventMask);
  173.     else
  174.         SysBeep(1);
  175. }
  176.  
  177.  
  178.  
  179. ///--------------------------------------------------------------------------------------
  180. //    Globals for HideMenuBar and ShowMenuBar
  181. ///--------------------------------------------------------------------------------------
  182.         
  183. RgnHandle    gOldVisRgn = NULL;    // visRgn of window before hiding menu bar
  184. RgnHandle    gUpdateRgn = NULL;    // region returned to user
  185. short        gOldMBarHeight;
  186.  
  187.  
  188. ///--------------------------------------------------------------------------------------
  189. //    SWHideMenuBar - expands the vis region of grafPort to cover the entire window, which
  190. // will allow you to draw in the top of that window to erase the menu bar. This is a
  191. // simple routine designed for programs with only one window that covers the menu bar.
  192. // If you need to expand the region of more than one window, you need a different routine.
  193. // Be sure to make the window visible before calling this. HideMenuBar returns the
  194. // region of the menu bar and corners of the screen, in case you want to erase or
  195. // draw in that area. Remember to dispose this region when done with it!
  196. ///--------------------------------------------------------------------------------------
  197.  
  198. RgnHandle    SWHideMenuBar(GrafPtr grafPort)
  199. {
  200.     RgnHandle newVisRgn;
  201.     GrafPtr savePort;
  202.     
  203.     if (gOldVisRgn != NULL)
  204.         return NULL;
  205.  
  206.     GetPort(&savePort);
  207.     SetPort(grafPort);
  208.     
  209.     gOldMBarHeight = LMGetMBarHeight();
  210.     LMSetMBarHeight( 0 );        // Keeps things like SuperClock from coming on.
  211.  
  212.         // save off vis region
  213.     gOldVisRgn = NewRgn();
  214.     CopyRgn(grafPort->visRgn, gOldVisRgn);
  215.  
  216.         // expand the vis region of the port rect to be completely rectangular
  217.     newVisRgn = NewRgn();
  218.     RectRgn(newVisRgn, &grafPort->portRect);
  219.     CopyRgn(newVisRgn, grafPort->visRgn);
  220.     DisposeRgn(newVisRgn);
  221.     
  222.         // dispose gUpdateRgn from previous call to HideMenuBar in case user forgot to
  223.     if (gUpdateRgn != NULL)
  224.     {
  225.         DisposeRgn(gUpdateRgn);
  226.         gUpdateRgn = NULL;
  227.     }
  228.     
  229.         // set gUpdateRgn to region of rounded corners and menu bar
  230.     gUpdateRgn = NewRgn();
  231.     CopyRgn(gOldVisRgn, gUpdateRgn);
  232.     DiffRgn(grafPort->visRgn, gUpdateRgn, gUpdateRgn);
  233.  
  234.     SetPort(savePort);
  235.     return gUpdateRgn;
  236. }
  237.  
  238.  
  239. ///--------------------------------------------------------------------------------------
  240. //    KeepMenuBarHidden - call this during your main animation loop to make sure the
  241. //    window's visRgn stays the same as the window's portRect. (Utilities like the Control
  242. //    strip can mess it up.) Only necessary if you use CopyBits as your screenDrawProc and
  243. //  you find that the Control Strip, Dialog Boxes, or other things cause your window's
  244. //  region to be changed so you can't over the portion where the menu bar is anymore.
  245. ///--------------------------------------------------------------------------------------
  246.  
  247. void KeepMenuBarHidden(GrafPtr grafPort)
  248. {
  249.     Rect    regionRect;
  250.     
  251.     regionRect = (**grafPort->visRgn).rgnBBox;
  252.     
  253.         // Fix the region only if it needs fixing
  254.     if (regionRect.top != grafPort->portRect.top || 
  255.         regionRect.bottom != grafPort->portRect.bottom ||
  256.         regionRect.left != grafPort->portRect.left ||
  257.         regionRect.right != grafPort->portRect.right )
  258.     {
  259.         RectRgn(grafPort->visRgn, &grafPort->portRect);
  260.     }
  261. }
  262.  
  263.  
  264. ///--------------------------------------------------------------------------------------
  265. //    SWShowMenuBar - restores the grafPort to the way it was before the call to HideMenuBar.
  266. //    Make sure to call this after every call to HideMenuBar to dispose of gOldVisRgn.
  267. //    NOTE: On System 8, make sure to call SWShowMenuBar before displaying any dialog boxes.
  268. //    If you do it afterwards, it won't redraw the rounded corners.
  269. ///--------------------------------------------------------------------------------------
  270.  
  271. void SWShowMenuBar(GrafPtr grafPort)
  272. {
  273.     GrafPtr savePort;
  274.     RgnHandle junkRgn;
  275.     
  276.     if (gOldVisRgn == NULL)
  277.         return;
  278.  
  279.     GetPort(&savePort);
  280.     SetPort(grafPort);
  281.     
  282.     LMSetMBarHeight( gOldMBarHeight );
  283.  
  284.         // fill the rounded corners of the screen with black again
  285.     junkRgn = NewRgn();
  286.     CopyRgn(gOldVisRgn, junkRgn);
  287.     DiffRgn(grafPort->visRgn, junkRgn, junkRgn);
  288.     ForeColor(blackColor);
  289.  
  290.     FillRgn(junkRgn, &qd.black);
  291.     
  292.     DisposeRgn(junkRgn);
  293.  
  294.         // restore the old vis region
  295.     CopyRgn(gOldVisRgn, grafPort->visRgn);
  296.     DisposeRgn(gOldVisRgn);
  297.     gOldVisRgn = NULL;
  298.  
  299.         // Dispose this region which was created by SWHideMenuBar
  300.     if (gUpdateRgn != NULL)
  301.     {
  302.         DisposeRgn(gUpdateRgn);
  303.         gUpdateRgn = NULL;
  304.     }
  305.  
  306.     DrawMenuBar();
  307.     
  308.     SetPort(savePort);
  309. }
  310.  
  311.  
  312. #pragma mark -
  313. ///--------------------------------------------------------------------------------------
  314. //    GetDepthFromGlobalRect
  315. ///--------------------------------------------------------------------------------------
  316.  
  317. short GetDepthFromGlobalRect( Rect* globalRect )
  318. {
  319.     SysEnvRec        theSERec;
  320.     GDHandle        rectGDH;
  321.     short            depth;
  322.     
  323.     
  324.     SysEnvirons( 2, &theSERec );
  325.     if ( !theSERec.hasColorQD )                // no colorQD?
  326.     {
  327.         depth = 1;
  328.     }
  329.     else
  330.     {    
  331.         rectGDH = GetMaxDevice( globalRect );
  332.         depth = GetGDeviceDepth( rectGDH );        
  333.     }
  334.     return depth;
  335. }
  336.  
  337.  
  338. ///--------------------------------------------------------------------------------------
  339. //    GetDepthFromWindow
  340. ///--------------------------------------------------------------------------------------
  341.  
  342. short GetDepthFromWindow( WindowPtr theWindow )
  343. {
  344.     SysEnvRec        theSERec;
  345.     GWorldPtr        oldGWorld, windowGWld;
  346.     GDHandle        oldGDH, windowGDH;
  347.     short            depth;
  348.     
  349.     
  350.     SysEnvirons( 2, &theSERec );
  351.     if ( !theSERec.hasColorQD )                // no colorQD?
  352.         depth = 1;
  353.     else
  354.     {    
  355.         GetGWorld( &oldGWorld, &oldGDH );
  356.         SetPort( theWindow );
  357.         GetGWorld( &windowGWld, &windowGDH );
  358.         
  359.         depth = GetGDeviceDepth( windowGDH );
  360.         
  361.         SetGWorld( oldGWorld, oldGDH );
  362.     }
  363.     return depth;
  364. }
  365.  
  366.  
  367. ///--------------------------------------------------------------------------------------
  368. //    GetGDeviceDepth - to get the depth of the main monitor,
  369. //    simply do this: GetGDeviceDepth( GetMainDevice() );
  370. ///--------------------------------------------------------------------------------------
  371.  
  372. short GetGDeviceDepth( GDHandle theGDH )
  373. {
  374.     SysEnvRec        theSERec;
  375.     PixMapHandle    thePixMap;
  376.     
  377.     
  378.     SysEnvirons( 2, &theSERec );
  379.     if ( !theSERec.hasColorQD )                // no colorQD?
  380.         return 1;
  381.     else
  382.     {
  383.         thePixMap = (**theGDH).gdPMap;
  384.         return (**thePixMap).pixelSize;     // Depth in bits (1,2,4...)
  385.     }
  386. }
  387.  
  388.  
  389. ///--------------------------------------------------------------------------------------
  390. //    RestoreSystemPalette - if your game uses a custom palette, call this when switching
  391. //    to the Finder or some other app if you want it to have its original palette back.
  392. ///--------------------------------------------------------------------------------------
  393.  
  394. void    RestoreSystemPalette( void )
  395. {
  396.     RestoreDeviceClut(nil);
  397.     PaintBehind(FrontWindow(), GetGrayRgn());
  398.     PaintOne(nil, GetGrayRgn());
  399.     DrawMenuBar();
  400. }
  401.  
  402.  
  403. ///--------------------------------------------------------------------------------------
  404. //    HasSystem7
  405. ///--------------------------------------------------------------------------------------
  406.  
  407. Boolean        HasSystem7( void )
  408. {
  409.     long    gestaltResponse;
  410.     OSErr    err;
  411.     
  412.     err = Gestalt( gestaltSystemVersion, &gestaltResponse );
  413.     return ( err == noErr && ((unsigned long)gestaltResponse >= 0x0700));
  414. }
  415.  
  416.  
  417. #pragma mark -
  418. // Uncomment the following lines if you're using an older version of
  419. // Universal headers and this constant is not defined.
  420. /*
  421. enum {
  422.     _ControlStripDispatch = 0xAAF2
  423. };
  424. */
  425.  
  426.  
  427. // Globals
  428. Boolean gControlStripWasVisible = false;    // true if the control strip was visible before we hid it
  429.  
  430. ///--------------------------------------------------------------------------------------
  431. //    HideControlStrip - Hides the control strip if it's installed and visible, and remembers
  432. //    its old visibility state. Does nothing otherwise. IMPORTANT: This function should be
  433. //    called *before* SWHideMenuBar if you use SWHideMenuBar.
  434. ///--------------------------------------------------------------------------------------
  435.  
  436. void HideControlStrip( void )
  437. {
  438.     OSErr    err;
  439.     long    flags;
  440.  
  441.         // Check if the control strip is installed
  442.     err = Gestalt(gestaltControlStripAttr, &flags);
  443.     if (err != noErr || !(flags & (1 << gestaltControlStripExists)))
  444.         return;        // it's not installed
  445.     
  446.         // Make ultra-sure the trap is defined
  447.     if (GetToolTrapAddress(_ControlStripDispatch) == GetToolTrapAddress(_Unimplemented))
  448.         return;
  449.     
  450.         // Hide it if it's visible
  451.     if (SBIsControlStripVisible())
  452.     {
  453.         gControlStripWasVisible = true;
  454.         SBShowHideControlStrip(false);
  455.     }
  456. }
  457.  
  458.  
  459. ///--------------------------------------------------------------------------------------
  460. //    RestoreControlStrip - Restores the control strip visibility to what it was before it
  461. //    was hidden.
  462. ///--------------------------------------------------------------------------------------
  463.  
  464. void RestoreControlStrip( void )
  465. {
  466.     if (gControlStripWasVisible) // this will never be true if the control strip was not installed
  467.     {
  468.         gControlStripWasVisible = false;
  469.         SBShowHideControlStrip(true);
  470.     }
  471. }
  472.  
  473.  
  474. ///--------------------------------------------------------------------------------------
  475. //    The following functions are called internally.
  476. ///--------------------------------------------------------------------------------------
  477.  
  478. // If calling from non-68k code, we have to use the Mixed Mode Manager to call the
  479. // Control Strip functions, since there is no PowerPC library for Control Strip calls (yet).
  480. // Reference: http://developer.apple.com/qa/ops/ops15.html
  481.  
  482. #if GENERATINGCFM
  483.  
  484. pascal Boolean SBIsControlStripVisible (void)
  485. {
  486.     ProcInfoType info =    kD0DispatchedPascalStackBased
  487.                         | RESULT_SIZE(SIZE_CODE(sizeof(Boolean)))
  488.                         | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kFourByteCode);
  489.  
  490.     return CallUniversalProc(GetToolTrapAddress(_ControlStripDispatch), info, 0);
  491. }
  492.  
  493. pascal void SBShowHideControlStrip(Boolean showIt)
  494. {
  495.     ProcInfoType info =    kD0DispatchedPascalStackBased
  496.                         | DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kFourByteCode)
  497.                         | DISPATCHED_STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(showIt)));
  498.  
  499.     CallUniversalProc(GetToolTrapAddress(_ControlStripDispatch), info, 1, showIt);
  500. }
  501.  
  502. #else   //  not GENERATINGCFM
  503.  
  504. // If we're not generating CFM, assume the 68K inlines in the headers apply instead.
  505.  
  506. #endif
  507.  
  508.